#ifndef _HTTPPROXY_H
#define _HTTPPROXY_H

#include <map>
#include <vector>
#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/ptr_container/ptr_map.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <boost/regex.hpp>
#include <hippolib/system/thread.hpp>
#include <hippolib/net/httpheader.hpp>
#include "../common/logmanager.h"
#include "httpconfig.h"
#include "httpusermgr.h"

class ProxyStatus
{
public:
	ProxyStatus() :
		m_name(""), m_resolved_ip(boost::asio::ip::address_v4::loopback()),
		m_isalive(false), m_lastcheck(boost::posix_time::second_clock::local_time()) {}
	std::string getName() const {return m_name;}
	void setName(const std::string & name) {m_name = name;}
	boost::asio::ip::address_v4 getResolvedIp() const {return m_resolved_ip;}
	void setResolvedIp(const boost::asio::ip::address_v4 & ip) { m_resolved_ip = ip;}
	bool isAlive() {return m_isalive;}
	void setAlive(bool isalive) {m_isalive = isalive;}
	boost::posix_time::ptime getLastCheckTime() const {return m_lastcheck;}
	void setLastCheckTime(const boost::posix_time::ptime & lastcheck) {m_lastcheck = lastcheck;}
private:
	std::string m_name;
	boost::asio::ip::address_v4 m_resolved_ip;
	bool m_isalive;
	boost::posix_time::ptime m_lastcheck;
};

class HTTPProxy : public hippolib::thread
{
public:
	static const std::string PACKAGE_NAME;
	static const std::string PACKAGE_VERSION;
	static const std::string DEFAULT_SSL_RESPONSE;
	static const std::string DEFAULT_UNAUTHORIZED_RESPONSE;
	static const boost::regex URL_REGEX;

	virtual ~HTTPProxy();
	static HTTPProxy& getInstance();

	void Initialize();
	void StartProxy();
	void StopProxy();
	void setConfig(const HTTPConfig & config) {m_config = config;}
	HTTPConfig& getConfig() {return m_config;}

protected:
	
	HTTPProxy();
	
private:
	
	static HTTPProxy m_instance;
	
	enum header_errors
	{
		CORRECT = 0,
		NEED_AUTH,
		AUTH_NOTSUPPORT,
		AUTH_FAIL
	};

	void run();
	void proxy_check_thread();
	void process_client_headers(std::map<std::string, hippolib::httpheader, hippolib::HeaderKeyComparer> & headers, int & retcode);
	int search_acl(const boost::asio::ip::address_v4 & srcip,
						const std::string & host,
						const boost::asio::ip::address_v4 & hostip);
	UpstreamProxy search_upstream(const boost::asio::ip::address_v4 & srcip,
									const std::string & host,
									const boost::asio::ip::address_v4 & hostip);
	void handle_accept(boost::shared_ptr<boost::asio::ip::tcp::socket> clientsock,
						const boost::system::error_code & error);

	HTTPConfig m_config;

	// User accounts
	HTTPUserManager m_usermgr;

	// Upstream proxy status
	std::map<std::string, ProxyStatus> m_proxystatus;
	typedef std::map<std::string, ProxyStatus>::iterator PXYSTS_ITER;

	// Upstream proxy check thread
	boost::thread *m_proxy_check_thread;
	
	// For internal networking use
	boost::asio::io_service m_ioservice;
	boost::asio::ip::tcp::acceptor m_acceptor;

	//
	static std::vector<std::string> SKIP_HEADERS;

	log4cxx::LoggerPtr m_logger;
	log4cxx::LoggerPtr m_access_logger;
};

#endif
